package security.SecurityUtil.jwt;/**
 * @Auther: liyipeng
 * @Date: 2020/1/16 15:52
 * @Description:
 */

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import finals.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.www.NonceExpiredException;
import security.SecurityUtil.login.CustomUserDetailService;
import security.util.RedisUtil;

import java.util.Calendar;

/**
 * <p>类名: JwtAuthenticationProvider</p>
 * <p>描述:TODO</p>
 * <p>创建人: liyp</p>
 * <p>创建时间: 2020/1/16 15:52</p>
 * <p>@version 2.0  </p>
 * <p>修改内容: ......</p>
 * <p>修改说明: ......</p>
 * <p>修改时间: ......</p>
 * <p>修改人: ......</p>
 * <p>每次修改，请增加上述修改信息说明</>
 */
public class JwtAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    RedisUtil redisUtil;

    private CustomUserDetailService customUserDetailService;

    public JwtAuthenticationProvider(CustomUserDetailService customUserDetailService) {
        this.customUserDetailService = customUserDetailService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        DecodedJWT jwt = ((JwtAuthenticationToken)authentication).getToken();
      /*  if(jwt.getExpiresAt().before(Calendar.getInstance().getTime()))
            throw new NonceExpiredException("Token expires");*/  //不校验jwt的本身过期时间，用redis来续命sign值
        String username = jwt.getSubject();
        UserDetails user = customUserDetailService.getUserLoginInfo(username);
        if(user == null || user.getPassword()==null)
        //这里的password是指的缓存中生成jwt所需要的前缀，不是用户的password，如果不存在表示已经过期
            throw new NonceExpiredException("Token expires");
        String encryptSalt = user.getPassword();
        try {
            Algorithm algorithm = Algorithm.HMAC256(encryptSalt);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withSubject(username)
                    .build();
            verifier.verify(jwt.getToken());
        } catch (Exception e) {
            throw new BadCredentialsException("JWT token verify fail", e);
        }
        //成功后返回认证信息，filter会将认证信息放入SecurityContext
        JwtAuthenticationToken token = new JwtAuthenticationToken(user, jwt, user.getAuthorities());
        //认证成功后，对token前缀进行续命，延长过期时间
        delayTokenExpireTime(user);
        return token;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.isAssignableFrom(JwtAuthenticationToken.class);
    }

    public void delayTokenExpireTime(UserDetails user){
        redisUtil.delayKeyTime(Constant.TOKEN_PERFFEX+user.getUsername(),user.getPassword(),3600);
    }
}
